<canvas id="scene"></canvas>
<script>

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = "anonymous";
    img.src = url;
    img.onload = () => resolve(img);
    img.onerror = reject;
  });
}

function loadRgbaDataFromImage(img) {
  const canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0, img.width, img.height);
  return loadRgbaDataFromCanvas(canvas);
}

function loadRgbaDataFromCanvas(canvas) {
  const ctx = canvas.getContext('2d');
  const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  return new Int32Array(imgData.data);
}

function renderRgbaData(canvas, data, width, height, smooth) {
  canvas.width = width;
  canvas.height = height;

  const ctx = canvas.getContext('2d');
  const img = ctx.getImageData(0, 0, width, height);
  ctx.imageSmoothingEnabled = Boolean(smooth);

  const vals = new Uint8ClampedArray(data);
  img.data.set(vals);
  ctx.putImageData(img, 0, 0);

  return canvas;
}

function interpolateRgba(data0, data1, alpha, width, height, channels){
  const out = new Uint8ClampedArray(data0.length);
  const alpha0 = 1 - alpha;
  const alpha1 = alpha;
  for (let x = 0; x < width; ++x) {
    for (let y = 0; y < height; ++y) {
      for (let c = 0; c < channels; ++c) {
        let ix = (y*width + x) * channels + c;
        out[ix] = data0[ix] * alpha0 + data1[ix] * alpha1;
      }
    }
  }
  return out;
}

async function loadRgbaDataFromUrl(url) {
  const img = await loadImage(url);
  return loadRgbaDataFromImage(img);
}

// async/await
(async function(){
  const width = 500;
  const height = 375;
  const channels = 4;
  const canvas = document.getElementById("scene");
  const pixels = await loadRgbaDataFromUrl("data/bike.jpg");
  const object = await loadRgbaDataFromUrl("data/bike_object.png");
  const layover = interpolateRgba(pixels, object, 0.5, width, height, channels);

  renderRgbaData(canvas, pixels, width, height);
  
  canvas.onmouseover = () => renderRgbaData(canvas, layover, width, height);
  canvas.onmouseleave = () => renderRgbaData(canvas, pixels, width, height);
}());

</script>